using LF.Common;
using LF.Domain.Entities;
using LF.Domain.Helper;
using LF.Shared.Dtos.Out;
using System;
using System.Collections.Generic;
using System.Linq;

namespace LF.Domain.Services.Iml
{
    public class MenuManagerService : IMenuManagerService
    {
        private readonly IGlobalManagerService _globalManager;

        public MenuManagerService(IGlobalManagerService globalManager)
        {
            _globalManager = globalManager;
        }

        public List<Menu> All(int index, int pageSize, string? key)
        {
            var query = FreeSqlHelper.DbContext.Queryable<Menu>();
            if (!key.IsNullOrWhiteSpace())
            {
                query = query.Where(p => p.Name.Contains(key) || p.Code.Contains(key));
            }
            var list = query.Where(p => !p.IsDelete)
                .OrderBy(p => p.OrderNo)
                .OrderByDescending(p => p.UpdateTime)
                .Page(index, pageSize)
                .ToList();
            return list;
        }

        public long Count(string? key)
        {
            var query = FreeSqlHelper.DbContext.Queryable<Menu>();
            if (!key.IsNullOrWhiteSpace())
            {
                query = query.Where(p => p.Name.Contains(key) || p.Code.Contains(key));
            }
            return query.Where(p => !p.IsDelete).Count();
        }

        public List<Menu> GetMenuTree()
        {
            var allMenus = GetAll();
            var query = allMenus.Where(m => !m.ParentId.HasValue);
            var rootMenus = query
                .OrderBy(m => m.OrderNo)
                .ToList();
            
            foreach (var menu in rootMenus)
            {
                BuildMenuTree(menu, allMenus);
            }
            
            return rootMenus;
        }

        private void BuildMenuTree(Menu parent, List<Menu> allMenus)
        {
            parent.Children = allMenus.Where(m => m.ParentId == parent.Id)
                .OrderBy(m => m.OrderNo)
                .ToList();
            foreach (var child in parent.Children)
            {
                BuildMenuTree(child, allMenus);
            }
        }

        public List<Menu> GetAll()
        {
            return FreeSqlHelper.DbContext.Queryable<Menu>()
                .Where(p => !p.IsDelete)
                .OrderBy(p => p.OrderNo)
                .ToList();
        }

        public List<Menu> GetMenuWithChildren(Guid menuId)
        {
            var menu = FreeSqlHelper.DbContext.Queryable<Menu>()
                .Where(p => p.Id == menuId && !p.IsDelete)
                .First();

            if (menu == null)
                return new List<Menu>();

            var result = new List<Menu> { menu };
            var children = GetChildMenus(menuId);
            result.AddRange(children);
            return result;
        }

        private List<Menu> GetChildMenus(Guid parentId)
        {
            var children = FreeSqlHelper.DbContext.Queryable<Menu>()
                .Where(p => p.ParentId == parentId && !p.IsDelete)
                .ToList();

            var result = new List<Menu>(children);
            foreach (var child in children)
            {
                var grandChildren = GetChildMenus(child.Id);
                result.AddRange(grandChildren);
            }
            return result;
        }

        public bool CheckMenuCodeExists(string menuCode, Guid? excludeId = null)
        {
            var query = FreeSqlHelper.DbContext.Queryable<Menu>()
                .Where(p => p.Code == menuCode && !p.IsDelete);
                
            if (excludeId.HasValue)
            {
                query = query.Where(p => p.Id != excludeId.Value);
            }
            
            return query.Any();
        }

        public string GenerateMenuCode(Guid? parentId)
        {
            // 获取父菜单编码
            string parentCode = "";
            if (parentId.HasValue)
            {
                var parent = FreeSqlHelper.DbContext.Queryable<Menu>()
                    .Where(p => p.Id == parentId.Value && !p.IsDelete)
                    .First();
                if (parent != null)
                {
                    parentCode = parent.Code;
                }
            }

            // 获取同级菜单数量
            var count = FreeSqlHelper.DbContext.Queryable<Menu>()
                .Where(p => p.ParentId == parentId && !p.IsDelete)
                .Count();

            // 生成三位数编码
            var newCode = (count + 1).ToString().PadLeft(3, '0');
            
            // 组合完整编码
            return $"{parentCode}{newCode}";
        }

        public List<string> GetPermissionCodes(Guid userId)
        {
            try
            {
                // 检查是否是sysadmin用户
                var user = FreeSqlHelper.DbContext.Queryable<User>()
                    .Where(u => u.Id == userId && !u.IsDelete)
                    .First();

                if (user != null && user.UserName == "sysadmin")
                {
                    // sysadmin用户拥有所有权限
                    var allPermissions = FreeSqlHelper.DbContext.Queryable<Permission>()
                        .Where(m => !m.IsDelete)
                        .ToList(m => m.Code);
                    return allPermissions.Distinct().ToList();
                }

                // 简化实现：直接使用SQL查询获取用户的所有权限编码
                // 1. 获取用户所有角色
                var roles = FreeSqlHelper.DbContext.Queryable<UserRole>()
                    .Where(ur => ur.UserId == userId)
                    .ToList(ur => ur.RoleId);

                if (roles.Count == 0)
                    return new List<string>();

                var menus=FreeSqlHelper.DbContext.Queryable<RoleMenu>()
                    .Where(ur => roles.Any(p=>p==ur.RoleId))
                    .ToList(ur => ur.MenuId);

                // 2. 从Menu表中提取所有有效的权限编码，不直接映射ID
                // 这种方法避免了 Menu.Id 和 RoleMenu.MenuId 类型不匹配的问题
                // 只返回激活状态(active=true)的菜单权限编码
                var permissionCodes = FreeSqlHelper.DbContext.Queryable<Menu>()
                    .Where(m => !m.IsDelete && !string.IsNullOrEmpty(m.Permission) && m.Status==1&& menus.Any(p=>p==m.Id))
                    .ToList(m => m.Permission);

                // 如果系统对权限要求不严格，可以直接返回所有权限编码
                return permissionCodes.Distinct().ToList();
            }
            catch (Exception ex)
            {
                // 添加异常处理，确保出错时至少返回空列表而不是抛出异常
                Console.WriteLine($"GetPermissionCodes error: {ex.Message}");
                return new List<string>();
            }
        }

        /// <summary>
        /// 获取用户菜单树
        /// </summary>
        public List<Menu> GetUserMenuTree(Guid userId)
        {
            // 检查是否是sysadmin用户
            var user = FreeSqlHelper.DbContext.Queryable<User>()
                .Where(u => u.Id == userId && !u.IsDelete)
                .First();

            if (user != null && user.UserName == "sysadmin")
            {
                // sysadmin用户可以访问所有菜单
                var allMenusForAdmin = GetAll().Where(m => m.Status == 1).ToList();
                var rootMenusForAdmin = BuildMenuTree(allMenusForAdmin, null);
                return rootMenusForAdmin;
            }

            // 获取用户角色
            var userRoles = _globalManager.ToList<UserRole>(ur => ur.UserId == userId && !ur.IsDelete);
            if (!userRoles.Any())
            {
                return new List<Menu>();
            }

            var roleIds = userRoles.Select(ur => ur.RoleId).ToList();

            // 获取角色菜单权限
            var roleMenus = _globalManager.ToList<RoleMenu>(rm => roleIds.Contains(rm.RoleId) && !rm.IsDelete);
            if (!roleMenus.Any())
            {
                return new List<Menu>();
            }

            var menuIds = roleMenus.Select(rm => rm.MenuId).Distinct().ToList();

            // 获取菜单
            var allMenus = _globalManager.ToList<Menu>(m => menuIds.Contains(m.Id) && !m.IsDelete && m.Status == 1);

            // 构建菜单树
            var rootMenus = BuildMenuTree(allMenus, null);

            return rootMenus;
        }

        private List<Menu> BuildMenuTree(List<Menu> allMenus, Guid? parentId)
        {
            var children = allMenus.Where(m => m.ParentId == parentId).OrderBy(m => m.OrderNo).ToList();
            foreach (var child in children)
            {
                child.Children = BuildMenuTree(allMenus, child.Id);
            }
            return children;
        }
    }
} 